/**
  * @file    b2p.c
  * @author  伍勃 (wushifu32@163.com)
  * @version V0.0.1
  * @date    2016-01-14
  * @brief   将单色BMP图片转成热敏打印机的位图打印输出
  */
#include "b2p.h"

const ARRAY3 skip_cmd = {0x1B, 0x4A, 0x00};

int main(int argc, char* argv[])
{
    FILE* fin = NULL;
    FILE* fout = NULL;
    BITMAP_FILE bmp;
	PRINTER_FILE_HEADER printer_header;
    int file_error = 0;
	int i,j,k,h;
	
	PRINTER_BLOCK_NODE printer_block;
	IMAGE_LINE_NODE* temp = NULL;
	IMAGE_LINE_NODE* top = NULL;	
	PRINTER_BMP_CMD cmd;
	
	int image_line_size;
	UINT8 column_temp;
	UINT8 line_temp;	
  
    /* 打开文件 */
    if (argc < 2)
    {
        printf("error: Too few parameters!\n");
        return 0;
    }    
    if (argc == 2)
    {
        fin = fopen(argv[1],"rb");
        fout = fopen("a.pbin", "wb+");
    }
    else
    {
        fin = fopen(argv[2],"rb");
        fout = fopen(argv[1], "wb+");
    }    
    if ((fin == NULL) || (fout == NULL))
    {
        printf("error: Open file failed!");
        goto end;
    }
    
    /* 识别文件头 */
    if (Get_BMP_File(fin, &bmp) != 0)
    {
        printf("error: The bmp file is error!\n");
        goto end;
    }
    if ((bmp.header.bfType != FILE_TYPE_BM) && \
        (bmp.header.bfType != FILE_TYPE_BA) && \
        (bmp.header.bfType != FILE_TYPE_CI) && \
        (bmp.header.bfType != FILE_TYPE_CP) && \
        (bmp.header.bfType != FILE_TYPE_IC) && \
        (bmp.header.bfType != FILE_TYPE_PI))
    {
        printf("error: The bmp file is error!\n");
        goto end;
    }
    if (bmp.info.biBitCount != 1)
    {
        printf("error: The file is not single color bmp!\n");
        goto end;
    }
    if (bmp.info.biCompression != 0)
    {
        printf("error: The bmp file is compressed!\n");
        goto end;
    }
    
    /* 写输出文件头 */
    printer_header.type = FILE_TYPE_AD;
	printer_header.offset = sizeof(PRINTER_FILE_HEADER);
	printer_header.width = bmp.info.biWidth;
	printer_header.height = (bmp.info.biHeight + 23) / 24;
	printer_header.size = (printer_header.width + 8) * printer_header.height * 3;
	printer_header.height = printer_header.height * 24;
	printer_header.reserve1 = 0;
	printer_header.reserve2 = 0;
	printer_header.reserve3 = 0;
	fwrite((void*)(&printer_header), sizeof(PRINTER_FILE_HEADER), 1, fout);
    
    /* 读取位图数据 */
	image_line_size = bmp.info.biSizeImage / bmp.info.biHeight;
    fseek(fin, bmp.header.bfOffBits, SEEK_SET);
	for(i = 0; i < bmp.info.biHeight; i++)
	{
		temp = (IMAGE_LINE_NODE*)malloc(sizeof(IMAGE_LINE_NODE));
		temp->bData = (UINT8*)malloc(image_line_size);
		fread((void*)temp->bData, 1, image_line_size, fin);
		temp->next = top;
		top = temp;
	}
	
	/* 转换为printer的位图块 */
	cmd.type = PRINTER_TYPE_BMP;
	cmd.mode = 33;
	cmd.size = bmp.info.biWidth;
	printer_block.column = (ARRAY3 *)malloc(bmp.info.biWidth * 3);
	for(i = 0, j = -1; i < bmp.info.biHeight; i++)
	{
		if ((i % 8) == 0)
		{
			column_temp = 0x80;
			j++;
		}
		else
		{
			column_temp >>= 1;
		}
	
		for(k = 0, h = -1; k < bmp.info.biWidth; k++)
		{
			if ((k % 8) == 0)
			{
				line_temp = 0x80;
				h++;
			}
			else
			{
				line_temp >>= 1;
			}
			
			if (top->bData[h] & line_temp)
				printer_block.column[k][j] &= ~column_temp;
			else
				printer_block.column[k][j] |= column_temp;
			
		}
		
		if (((i + 1) % 24) == 0)
		{
			Write_Printer_Command(fout, &cmd);
			fwrite((void*)(printer_block.column), 3, bmp.info.biWidth, fout);
            fwrite((void*)(&skip_cmd), 3, 1, fout);
			j = -1;
		}
		
		temp = top;
		top = temp->next;
		free(temp->bData);
		free(temp);
	}	
	for(; (i % 24) != 0; i++)
	{
		if ((i % 8) == 0)
		{
			column_temp = 0x80;
			j++;
		}
		else
		{
			column_temp >>= 1;
		}
		
		for(k = 0; k < bmp.info.biWidth; k++)
			printer_block.column[k][j] &= ~column_temp;
		
		if (((i + 1) % 24) == 0)
		{
			Write_Printer_Command(fout, &cmd);
			fwrite((void*)(printer_block.column), 3, bmp.info.biWidth, fout);
            fwrite((void*)(&skip_cmd), 3, 1, fout);
			j = -1;
		}
	}
	free(printer_block.column);
        
    end: \
    fclose(fin);
    fclose(fout);
    return 0;
}

static int Get_BMP_File(FILE* f, BITMAP_FILE* bmp)
{
    int error = -6;
    
    error += fread((void*)(&bmp->header.bfType), 2, 1, f);
    error += fread((void*)(&bmp->header.bfSize), 4, 1, f);
    error += fread((void*)(&bmp->header.bfReserved1), 2, 1, f);
    error += fread((void*)(&bmp->header.bfReserved2), 2, 1, f);
    error += fread((void*)(&bmp->header.bfOffBits), 4, 1, f);
    
    error += fread((void*)(&bmp->info), sizeof(BITMAP_INFO_HEADER), 1, f);
    
    return error;
}

static int Write_Printer_Command(FILE* f, PRINTER_BMP_CMD* cmd)
{
	fwrite((void*)(&cmd->type), 2, 1, f);
	fwrite((void*)(&cmd->mode), 1, 1, f);
	fwrite((void*)(&cmd->size), 2, 1, f);
}